﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace Runtime.Models {

    public interface IDFR_ReadOnlyListModel<T> : IDFR_Model, IReadOnlyListData<T> {
    }

    public interface IDFR_ListModel<T> : IDFR_ReadOnlyListModel<T>, IListData<T> {
    }

    public abstract class DFR_ListModel<T> : DFR_Model, IDFR_ListModel<T> {

        [Autowired]
        private readonly IListData<T> m_List;

        #region Implement by m_List
        public T this[int index] { get => m_List[index]; set => m_List[index] = value; }

        T IReadOnlyList<T>.this[int index] => ((IReadOnlyList<T>)m_List)[index];

        public int Count => m_List.Count;

        public bool IsReadOnly => m_List.IsReadOnly;

        public event IListDataAdded<T>.AddedDelegate Added {
            add {
                m_List.Added += value;
            }

            remove {
                m_List.Added -= value;
            }
        }

        public event IListDataRemoved<T>.RemovedDelegate Removed {
            add {
                m_List.Removed += value;
            }

            remove {
                m_List.Removed -= value;
            }
        }

        public event IListDataCleared<T>.ClearedDelegate Cleared {
            add {
                m_List.Cleared += value;
            }

            remove {
                m_List.Cleared -= value;
            }
        }

        public event IListDataUpdated<T>.UpdatedDelegate Updated {
            add {
                m_List.Updated += value;
            }

            remove {
                m_List.Updated -= value;
            }
        }

        public void Add(T item) {
            m_List.Add(item);
        }

        public IReadOnlyListData<T> AsReadOnly() {
            return m_List.AsReadOnly();
        }

        public IListData<T> AsReadWrite() {
            return m_List.AsReadWrite();
        }

        public void Clear() {
            m_List.Clear();
        }

        public bool Contains(T item) {
            return m_List.Contains(item);
        }

        public void CopyTo(T[] array, int arrayIndex) {
            m_List.CopyTo(array, arrayIndex);
        }

        public T Get(int index) {
            return m_List.Get(index);
        }

        public IEnumerator<T> GetEnumerator() {
            return m_List.GetEnumerator();
        }

        public int IndexOf(T item) {
            return m_List.IndexOf(item);
        }

        public void Insert(int index, T item) {
            m_List.Insert(index, item);
        }

        public bool Remove(T item) {
            return m_List.Remove(item);
        }

        public void RemoveAt(int index) {
            m_List.RemoveAt(index);
        }

        public bool TryGet(int index, out T value) {
            return m_List.TryGet(index, out value);
        }

        public void Update(int index, T value) {
            m_List.Update(index, value);
        }

        public void Update(int index, Action<T> updater) {
            m_List.Update(index, updater);
        }

        IEnumerator IEnumerable.GetEnumerator() {
            return ((IEnumerable)m_List).GetEnumerator();
        }

        public void NotifyChanged() => m_List.NotifyChanged();
        #endregion
    }
}